<?php
declare (strict_types=1);

namespace app\command;

use app\model\SysFiles;
use think\console\Command;
use think\console\Input;
use think\console\input\Option;
use think\console\Output;

class Pack extends Command
{
    protected function configure()
    {
        // 指令配置
        $this->setName('pack')
            ->addOption('rev', '', Option::VALUE_OPTIONAL, '版本号')
            ->addOption('desc', '', Option::VALUE_OPTIONAL, '更新说明')
            ->addOption('dir', '', Option::VALUE_OPTIONAL, '检索路径', [root_path().'app',root_path().'config',root_path().'route',root_path().'view'])
            ->setDescription('打包更新文件');
    }

    protected function execute(Input $input, Output $output)
    {
        // 指令输出
        //$output->writeln('pack');

        $rev = $input->getOption('rev');
        $desc = $input->getOption('desc');
        $dirs = $input->getOption('dir');

        #搜索并打包
        $res = $this->pack($dirs, $rev);

        #记录日志；
        $record = $this->process($res, $rev, $desc);

        //打包文件名
        $zipName = $rev.'_'.time().'.zip';

        if (!empty($record['cmd'])) {
           $zip =  exec('zip'.' '.$zipName .' ' . $record['cmd'], $outputs, $rc);
           $output->writeln($zip);
        }

    }


    /**
     * 打包方法
     * @param $path
     * @param $rev          版本号
     */
    public function pack(array $path, string $rev)
    {
        //利用git工具？有可能git提交了，本次却没更新该方法，所以要记录git的id？但回滚之类的有无法保证

        $num = count($path);
        $result = $this->range($num, $path);
        foreach ($result as $dir) {
            $dirs = $this->getPath($dir);
        }
        $sysFiles = SysFiles::getInstance();
        foreach ($dirs as $dir) {
            $files = [];
            foreach (glob($dir . '*') as $k => $filePath) {
                $fileName = basename($filePath);
                $files[$k][$fileName] = filemtime($filePath);
            }
            //找出文件夹下所有文件
            $res = $sysFiles->sync($dir, $files, $rev);
        }
        return $res;
    }

    /**
     * 递归获取 所有【文件夹】非文件
     * @param $dir //文件路径
     * @param $include //包含文件路径
     * @return array|bool
     */
    private function getPath($dir)
    {
        static $files = [];
        $filePaths = scandir($dir);  //加载其下面的路径
        foreach ($filePaths as $fn) {
            if ($fn == "." || $fn == "..") {
                continue;
            }
            $filePath = $dir . DIRECTORY_SEPARATOR . $fn;
            if (is_dir($filePath)) {
                $this->getPath($filePath);
            } else {
                $files[] = $filePath;
            }
        }
        return $files;
    }

    //生成器
    private function range($num, $arr)
    {
        for ($i = 0; $i < $num; $i++) {
            yield array_shift($arr);
        }
    }


    /**
     * 记录日志
     * @param $data
     * @param $rev
     * @param $desc
     */
    private function process($data, $rev, $desc)
    {
        $c = $u = $d = '';
        $cnum = $unum = $dnum = 0;
        $cmd = '';
        foreach ($data as $k => $v) {
            switch ($k) {
                case 'C':
                    $cnum = count($v);
                    $c .= implode("</br>", $v);
                    $cmd .= implode(" ", $v);
                    break;
                case 'U':
                    $unum = count($v);
                    $u .= implode("</br>", $v);
                    $cmd .= implode(" ", $v);
                    break;
                case 'D':
                    $dnum = count($v);
                    $d .= implode("</br>", $v);
                    break;
            }

        }

        $str = $this->log($rev, $desc, $cnum, $c, $unum, $u, $dnum, $d);
        $logPath = public_path() . 'static/rev/log/';
        if (!is_dir($logPath)) {
            mkdir($logPath, 0777, true);
        }

        $file = date("YmdHis") . '.html';
        file_put_contents($logPath . $file, $str);
        $res['logFile'] = request()->domain() . '/static/rev/log/' . date("YmdHis") . '.html';
        $res['cmd'] = $cmd;
        return $res;
    }

    /**
     * 组装日志
     * @param $rev  版本号
     * @param $desc 版本修改说明
     * @param $cnum 新增文件数量
     * @param $c    新增文件
     * @param $unum 修改文件数量
     * @param $u    修改文件
     * @param $dnum 删除文件数量
     * @param $d    删除文件
     * @return string
     */
    private function log($rev, $desc, $cnum, $c, $unum, $u, $dnum, $d)
    {
        $str = "<!DOCTYPE html>
                <html lang=\"en\">
                <head>
                    <meta charset=\"UTF-8\">
                    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">
                    <link href=\"https://cdn.jsdelivr.net/npm/bootstrap@5.1.0/dist/css/bootstrap.min.css\" rel=\"stylesheet\">
                    <title>{$rev}版本更新日志</title>
                </head>
                <body>
                <div class=\"container mt-5\">
                    <div class=\"jumbotron\">
                        <h1 class=\"lead\">V{$rev}版本更新日志</h1>
                        <p class=\"fs-6\">{$desc}</p>";

        if (!empty($c)) {
            $str .= "<hr class=\"my-3\">
                            <div class=\"text-success\">
                                <p class=\"mb-2\">新增文件: {$cnum}</p>
                                <p class=\"mx-lg-5\">
                                    {$c}
                                </p>
                            </div>";
        };

        if (!empty($u)) {
            $str .= "<hr class=\"my-3\">
            <div class=\"text-primary\">
                <p class=\"mb-2\">修改文件: {$unum}</p>
                <p class=\"mx-lg-5\">
                    {$u}
                </p>
            </div>";
        };

        if (!empty($d)) {
            $str .= "<hr class=\"my-3\">
            <div class=\"text-danger\">
                <p class=\"mb-2\">删除文件: {$dnum}</p>
                <p class=\"mx-lg-5\">
                    {$d}
                </p>
        </div>";
        };
        $str .= " </div></div></body></html>";
        return $str;
    }
}
